#pragma once

#include "Comm.hpp"
#include "Channel.hpp"

class EventLoop;

class TimerTask
{
private: 
    using task_t = std::function<void()>;
    using release_t = std::function<void()>;

public:
    TimerTask(uint64_t id, uint32_t delay, const task_t& cb)
        : _id(id), _timeout(delay), _task_cb(cb), _canceled(false) {}

    void SetRelease(const release_t& cb)
    {
        _release = cb;
    }

    uint32_t GetDelayTime()
    {
        return _timeout;
    }

    void Cancel()
    {
        _canceled = true;
    }

    ~TimerTask()
    {
        if (!_canceled)
        {
            _task_cb();
        }
        _release();
    }

private:
    uint64_t _id;       // 定时器任务对象 ID
    uint32_t _timeout;  // 定时任务的超时时间
    task_t _task_cb;    // 定时器对象要执行的定时任务
    release_t _release; // 用于删除 TimerWheel 中保存的定时器对象信息
    bool _canceled;     // 任务是否被取消 
};



class TimerWheel
{
private:
    using task_t = std::function<void()>;
    using ChannelOperator = std::function<void(Channel*)>;
    using RunInLoop = std::function<void(task_t)>;
    using weak_task = std::weak_ptr<TimerTask>;
    using ptr_task = std::shared_ptr<TimerTask>;

    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

    static int CreateTimerFD()
    {
        int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 0);
        if (timerfd < 0)
        {
            LOG(FATAL, "timerfd create error, errno: %d -> %s\n", errno, strerror(errno));
            exit(TIMERFD_CREATE_ERROR);
        }
        LOG(DEBUG, "timerfd_create success, timerfd: %d\n", timerfd);
        
        struct itimerspec itime;
        itime.it_value.tv_sec = 1;
        itime.it_value.tv_nsec = 0;
        itime.it_interval.tv_sec = 1;
        itime.it_interval.tv_nsec = 0;

        int ret = timerfd_settime(timerfd, 0, &itime, nullptr);
        if (ret < 0)
        {
            LOG(FATAL, "timerfd %d settime error, errno: %d -> %s\n", timerfd, errno, strerror(errno));
            exit(TIMERFD_SETTIME_ERROR);
        }
        LOG(DEBUG, "timerfd %d settime success\n", timerfd);
        
        return timerfd;
    }

    int ReadTimerFD()
    {
        uint64_t times;
        int ret = ::read(_timerfd, &times, sizeof times);
        if (ret < 0)
        {
            LOG(FATAL, "timerfd %d read times error, errno: %d -> %s\n", _timerfd, errno, strerror(errno));
            exit(TIMERFD_READ_ERROR);
        }
        LOG(DEBUG, "The timerfd %d timed out %lld times\n", _timerfd, times);
        return times;
    }

    void RunTimerTask()
    {
        // 每秒钟执行一次
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();
    }

    void OnTime()
    {
        int times = ReadTimerFD();
        for (int i = 0; i < times; ++i)
        {
            RunTimerTask();
        }
    }

    void TimerAddInLoop(uint64_t id, uint32_t delay, const task_t& cb)
    {
        ptr_task newtask = std::make_shared<TimerTask>(id, delay, cb);
        newtask->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        _timers[id] = weak_task(newtask);
        _wheel[(_tick + delay) % _capacity].push_back(newtask);
    }

    void TimerRefreshInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        ptr_task newtask = it->second.lock();
        int delay = newtask->GetDelayTime();
        _wheel[(_tick + delay) % _capacity].push_back(newtask);
    }

    void TimerCancelInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        ptr_task task = it->second.lock();
        if (task) task->Cancel();
    }

public:
    TimerWheel(EventLoop* loop)
        : _capacity(60),
          _tick(0),
          _loop(loop), 
          _wheel(_capacity),
          _timerfd(CreateTimerFD()),
          _timer_channel(std::make_unique<Channel>(_timerfd))
    {}

    void Init(const ChannelOperator& update, const ChannelOperator& remove)
    {
        _timer_channel->RegisterOperator(std::bind(update, _timer_channel.get()), std::bind(remove, _timer_channel.get()));
        _timer_channel->SetReadCallback(std::bind(&TimerWheel::OnTime, this));
        _timer_channel->EnableRead();
    }

    void TimerAdd(uint64_t id, uint32_t delay, const task_t& cb);
    void TimerRefresh(uint64_t id);
    void TimerCancel(uint64_t id);

    // 存在线程安全问题，只能在 EventLoop 线程内使用，不能被外界使用者调用                  
    bool HasTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end()) return true;
        else return false;
    }

    ~TimerWheel()
    {}

private:
    int _timerfd;   // 定时器描述符
    int _tick;      // 当前秒针，走到哪执行哪的任务
    int _capacity;  // 时间轮盘最大空间，即延迟时间
    EventLoop* _loop;

    std::unique_ptr<Channel> _timer_channel;
    std::vector<std::vector<ptr_task>> _wheel;
    std::unordered_map<uint64_t, weak_task> _timers;
};